{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 `ThreadPool` 析构时如果任务队列里还有未完成任务，常见的策略有两种：\n",
    "\n",
    "1. **抢占式退出**：不再继续取任务，尽快让工作线程返回并结束，队列里未执行的任务直接放弃。\n",
    "2. **优雅式退出**：让已经提交到队列中的任务继续跑完，等队列清空后再回收线程。\n",
    "\n",
    "对照你给出的两段 `threadFunc` 实现：\n",
    "\n",
    "| 版本                               | 行为               | 说明                                                         |\n",
    "| ---------------------------------- | ------------------ | ------------------------------------------------------------ |\n",
    "|`while (isPoolRunning_)`）| **放弃未完成任务** | 一旦外部把 `isPoolRunning_` 置为 `false`，即使队列里还有任务，线程会在下一次循环时因为 `if (!this->isPoolRunning_) { break; }` 直接跳出循环，不再取任务，剩余任务被丢弃。 |\n",
    "| `for(;;)`                | **等待任务执行完** | 线程持续从队列里取任务并执行；只有在队列已经空并且检测到 `isPoolRunning_ == false` 时，才会退出。这意味着析构时会把队列里的存量任务跑完，再回收线程。 |\n",
    "\n",
    "> 实际项目中通常会区分“优雅关闭”（等待任务完成）和“强制关闭”（放弃未完成任务）两种模式，并提供显式接口让调用者选择。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `while(isPoolRunning_)`: 直接放弃"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 消费者\n",
    "void ThreadPool::threadFunc(int threadID) {\n",
    "  auto lasttime = std::chrono::high_resolution_clock().now(); // 上次\n",
    "  while(isPoolRunning_) {\n",
    "    std::shared_ptr<Task> task;\n",
    "    {\n",
    "      // 获取锁\n",
    "      std::unique_lock<std::mutex> lock(taskQueMtx_);\n",
    "      std::cout << __PRETTY_FUNCTION__ << \":\" << __LINE__ << \" tid:\" << std::this_thread::get_id()\n",
    "                << \" 尝试获取任务\" << \"\\n\";\n",
    "\n",
    "      while (this->taskQue_.empty() && isPoolRunning_) { // 双重判断\n",
    "        if (this->poolMode_ == PoolMode::MODE_CACHED) {\n",
    "          if (std::cv_status::timeout ==\n",
    "              notEmpty_.wait_for(lock, std::chrono::seconds(1))) {\n",
    "            auto now = std::chrono::high_resolution_clock().now();\n",
    "            auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lasttime);\n",
    "            if (dur.count() >= THREAD_MAX_IDLE_TIME &&\n",
    "                this->curThreadSize_ > this->initThreadSize_) {\n",
    "              // 回收线程\n",
    "              threads_.erase(threadID); // 不使用? std::this_thread::getid();\n",
    "\n",
    "              curThreadSize_--;\n",
    "              std::cout << __PRETTY_FUNCTION__ << \":\" << __LINE__ \n",
    "                        << \" tid:\" << std::this_thread::get_id()\n",
    "                        << \", 回收: \" << threadID << \"\\n\";\n",
    "              return;\n",
    "            }\n",
    "          }\n",
    "        }\n",
    "        else {\n",
    "          notEmpty_.wait(lock);\n",
    "        }\n",
    "\n",
    "      }\n",
    "\n",
    "      if (!this->isPoolRunning_) {\n",
    "        break;\n",
    "      }\n",
    "\n",
    "      idleThreadSize_--;\n",
    "\n",
    "      // 取任务\n",
    "      task = taskQue_.front();\n",
    "      taskQue_.pop();\n",
    "      taskSize_--;\n",
    "\n",
    "      // 队列还有任务, 通知其他消费者\n",
    "      if (taskQue_.size() > 0) {\n",
    "        notEmpty_.notify_all();\n",
    "      }\n",
    "\n",
    "      // 通知生产者, 提交任务\n",
    "      notFull_.notify_all();\n",
    "    } // 释放锁\n",
    "\n",
    "    // 线程执行任务\n",
    "    if (task != nullptr) {\n",
    "      task->exec();\n",
    "    }\n",
    "\n",
    "    lasttime = std::chrono::high_resolution_clock().now();\n",
    "    idleThreadSize_++;\n",
    "  }\n",
    "\n",
    "  threads_.erase(threadID); // 执行任务完成后\n",
    "\n",
    "  std::cout << __PRETTY_FUNCTION__ << \":\" << __LINE__\n",
    "            << \" tid:\" << std::this_thread::get_id() << \", 回收: \" << threadID\n",
    "            << \"\\n\";\n",
    "  exitCond_.notify_all();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 只有一个线程参与了任务, 线程池出作用域, 其他线程直接退出了\n",
    "\n",
    "```shell\n",
    "void ThreadPool::threadFunc(int):107 tid:138943746012736 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):107 tid:138943729227328 尝试获取任务\n",
    "virtual Any CountSum::run() tid:138943746012736 CountSum开始\n",
    "void ThreadPool::threadFunc(int):107 tid:138943737620032 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):107 tid:138943720834624 尝试获取任务\n",
    "virtual Any CountSum::run() tid:138943746012736 CountSum结束\n",
    "void ThreadPool::threadFunc(int):107 tid:138943746012736 尝试获取任务\n",
    "计算结果：5050\n",
    "main over\n",
    "void ThreadPool::threadFunc(int):175 tid:138943746012736, 回收: 0\n",
    "void ThreadPool::threadFunc(int):175 tid:138943737620032, 回收: 1\n",
    "void ThreadPool::threadFunc(int):175 tid:138943729227328, 回收: 2\n",
    "void ThreadPool::threadFunc(int):175 tid:138943720834624, 回收: 3\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `for(;;)`: 等待任务执行完成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 消费者\n",
    "void ThreadPool::threadFunc(int threadID) {\n",
    "  auto lasttime = std::chrono::high_resolution_clock().now(); // 上次\n",
    "  for(;;) { // 保证任务执行完成\n",
    "    std::shared_ptr<Task> task;\n",
    "    {\n",
    "      // 获取锁\n",
    "      std::unique_lock<std::mutex> lock(taskQueMtx_);\n",
    "      std::cout << __PRETTY_FUNCTION__ << \":\" << __LINE__ << \" tid:\" << std::this_thread::get_id()\n",
    "                << \" 尝试获取任务\" << \"\\n\";\n",
    "\n",
    "      while (this->taskQue_.empty()) { // 双重判断\n",
    "        if (!this->isPoolRunning_) {\n",
    "          threads_.erase(threadID); // 执行任务完成后\n",
    "\n",
    "          std::cout << __PRETTY_FUNCTION__ << \":\" << __LINE__\n",
    "                    << \" tid:\" << std::this_thread::get_id() << \", 回收: \" << threadID\n",
    "                    << \"\\n\";\n",
    "          exitCond_.notify_all();\n",
    "          break;\n",
    "        }\n",
    "\n",
    "        if (this->poolMode_ == PoolMode::MODE_CACHED) {\n",
    "          if (std::cv_status::timeout ==\n",
    "              notEmpty_.wait_for(lock, std::chrono::seconds(1))) {\n",
    "            auto now = std::chrono::high_resolution_clock().now();\n",
    "            auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lasttime);\n",
    "            if (dur.count() >= THREAD_MAX_IDLE_TIME &&\n",
    "                this->curThreadSize_ > this->initThreadSize_) {\n",
    "              // 回收线程\n",
    "              threads_.erase(threadID); // 不使用? std::this_thread::getid();\n",
    "\n",
    "              curThreadSize_--;\n",
    "              std::cout << __PRETTY_FUNCTION__ << \":\" << __LINE__ \n",
    "                        << \" tid:\" << std::this_thread::get_id()\n",
    "                        << \", 回收: \" << threadID << \"\\n\";\n",
    "              return;\n",
    "            }\n",
    "          }\n",
    "        }\n",
    "        else {\n",
    "          notEmpty_.wait(lock, [this] {\n",
    "              return !taskQue_.empty() || !isPoolRunning_;\n",
    "          });\n",
    "        }\n",
    "      }\n",
    "\n",
    "      idleThreadSize_--;\n",
    "\n",
    "      // 取任务\n",
    "      task = taskQue_.front();\n",
    "      taskQue_.pop();\n",
    "      taskSize_--;\n",
    "\n",
    "      // 队列还有任务, 通知其他消费者\n",
    "      if (taskQue_.size() > 0) {\n",
    "        notEmpty_.notify_all();\n",
    "      }\n",
    "\n",
    "      // 通知生产者, 提交任务\n",
    "      notFull_.notify_all();\n",
    "    } // 释放锁\n",
    "\n",
    "    // 线程执行任务\n",
    "    if (task != nullptr) {\n",
    "      task->exec();\n",
    "    }\n",
    "\n",
    "    lasttime = std::chrono::high_resolution_clock().now();\n",
    "    idleThreadSize_++;\n",
    "  }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    "void ThreadPool::threadFunc(int):107 tid:138898002933312 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):107 tid:138897994540608 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):107 tid:138897986147904 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):107 tid:138897977755200 尝试获取任务\n",
    "virtual Any CountSum::run() tid:138897977755200 CountSum开始\n",
    "virtual Any CountSum::run() tid:138897977755200 CountSum结束\n",
    "void ThreadPool::threadFunc(int):107 tid:138897977755200 尝试获取任务\n",
    "计算结果：5050\n",
    "main over\n",
    "void ThreadPool::threadFunc(int):107 tid:138897977755200 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):107 tid:138897977755200 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):114 tid:138897977755200, 回收: 3\n",
    "void ThreadPool::threadFunc(int):107 tid:138898002933312 尝试获取任务\n",
    "void ThreadPool::threadFunc(int):114 tid:138898002933312, 回收: 0\n",
    "void ThreadPool::threadFunc(int):114 tid:138897994540608, 回收: 1\n",
    "void ThreadPool::threadFunc(int):114 tid:138897986147904, 回收: 2\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
